package com.insight.controller;

import com.insight.common.enums.DatabaseType;
import com.insight.dto.datasource.*;
import com.insight.service.ConnectionTestService;
import com.insight.service.DataSourceService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.List;
import java.util.Map;

/**
 * T039: 数据源管理REST API控制器
 * 实现数据源CRUD操作、连接测试的RESTful接口
 *
 * @author Insight Team
 */
@Slf4j
@RestController
@RequestMapping("/api/v1/datasources")
@RequiredArgsConstructor
@Tag(name = "Data Source Management", description = "数据源管理API - 支持多数据库类型的数据源配置和连接测试")
public class DataSourceController {

    private final DataSourceService dataSourceService;
    private final ConnectionTestService connectionTestService;

    @Value("${insight.security.encryption-key}")
    private String encryptionKey;

    /**
     * 创建数据源
     *
     * @param request 创建请求
     * @return 创建的数据源响应
     */
    @PostMapping
    @Operation(summary = "创建数据源", description = "创建新的数据源配置，密码将被加密存储")
    @ApiResponses({
            @ApiResponse(responseCode = "201", description = "创建成功",
                    content = @Content(schema = @Schema(implementation = DataSourceResponse.class))),
            @ApiResponse(responseCode = "400", description = "请求参数验证失败"),
            @ApiResponse(responseCode = "409", description = "数据源名称已存在")
    })
    public ResponseEntity<com.insight.common.response.ApiResponse<DataSourceResponse>> createDataSource(
            @Valid @RequestBody DataSourceCreateRequest request) {

        log.info("API: 创建数据源 - name={}, dbType={}", request.getName(), request.getDbType());

        DataSourceResponse response = dataSourceService.createDataSource(request, encryptionKey);

        URI location = URI.create(String.format("/api/v1/datasources/%d", response.getId()));
        return ResponseEntity.created(location).body(com.insight.common.response.ApiResponse.success(response));
    }

    /**
     * 根据ID获取数据源
     *
     * @param id 数据源ID
     * @return 数据源响应
     */
    @GetMapping("/{id}")
    @Operation(summary = "获取数据源详情", description = "根据ID查询数据源详细信息")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "查询成功",
                    content = @Content(schema = @Schema(implementation = DataSourceResponse.class))),
            @ApiResponse(responseCode = "404", description = "数据源不存在")
    })
    public ResponseEntity<DataSourceResponse> getDataSource(
            @Parameter(description = "数据源ID") @PathVariable Long id) {

        log.debug("API: 查询数据源 - id={}", id);

        DataSourceResponse response = dataSourceService.getDataSourceById(id);
        return ResponseEntity.ok(response);
    }

    /**
     * 分页查询所有数据源
     *
     * @param pageable 分页参数
     * @param dbType   数据库类型（可选）
     * @param enabled  是否启用（可选）
     * @return 数据源分页结果
     */
    @GetMapping
    @Operation(summary = "查询数据源列表", description = "分页查询数据源，支持按类型和启用状态过滤")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "查询成功")
    })
    public ResponseEntity<?> listDataSources(
            @PageableDefault(size = 20, sort = "createdAt") Pageable pageable,
            @Parameter(description = "数据库类型过滤") @RequestParam(required = false) DatabaseType dbType,
            @Parameter(description = "启用状态过滤") @RequestParam(required = false) Boolean enabled) {

        log.debug("API: 查询数据源列表 - page={}, size={}, dbType={}, enabled={}",
                pageable.getPageNumber(), pageable.getPageSize(), dbType, enabled);

        // 按数据库类型过滤
        if (dbType != null) {
            List<DataSourceResponse> responses = dataSourceService.listDataSourcesByType(dbType);
            // 将List转换为Page以保持API一致性
            Page<DataSourceResponse> page = new org.springframework.data.domain.PageImpl<>(
                responses, pageable, responses.size()
            );
            return ResponseEntity.ok(com.insight.common.response.ApiResponse.success(page));
        }

        // 按启用状态过滤
        if (enabled != null && enabled) {
            List<DataSourceResponse> responses = dataSourceService.listEnabledDataSources();
            // 将List转换为Page以保持API一致性
            Page<DataSourceResponse> page = new org.springframework.data.domain.PageImpl<>(
                responses, pageable, responses.size()
            );
            return ResponseEntity.ok(com.insight.common.response.ApiResponse.success(page));
        }

        // 默认分页查询
        Page<DataSourceResponse> page = dataSourceService.listDataSources(pageable);
        return ResponseEntity.ok(com.insight.common.response.ApiResponse.success(page));
    }

    /**
     * 更新数据源（不包括密码）
     *
     * @param id      数据源ID
     * @param request 更新请求
     * @return 更新后的数据源响应
     */
    @PutMapping("/{id}")
    @Operation(summary = "更新数据源", description = "更新数据源配置（不包括密码，密码请使用单独的接口）")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "更新成功",
                    content = @Content(schema = @Schema(implementation = DataSourceResponse.class))),
            @ApiResponse(responseCode = "404", description = "数据源不存在")
    })
    public ResponseEntity<DataSourceResponse> updateDataSource(
            @Parameter(description = "数据源ID") @PathVariable Long id,
            @Valid @RequestBody DataSourceUpdateRequest request) {

        log.info("API: 更新数据源 - id={}", id);

        DataSourceResponse response = dataSourceService.updateDataSource(id, request);
        return ResponseEntity.ok(response);
    }

    /**
     * 更新数据源密码
     *
     * @param id      数据源ID
     * @param payload 包含新密码的JSON
     * @return 204 No Content
     */
    @PatchMapping("/{id}/password")
    @Operation(summary = "更新数据源密码", description = "单独更新数据源连接密码")
    @ApiResponses({
            @ApiResponse(responseCode = "204", description = "更新成功"),
            @ApiResponse(responseCode = "404", description = "数据源不存在")
    })
    public ResponseEntity<Void> updatePassword(
            @Parameter(description = "数据源ID") @PathVariable Long id,
            @RequestBody Map<String, String> payload) {

        String newPassword = payload.get("password");
        if (newPassword == null || newPassword.isBlank()) {
            throw new IllegalArgumentException("密码不能为空");
        }

        log.info("API: 更新数据源密码 - id={}", id);

        dataSourceService.updatePassword(id, newPassword, encryptionKey);
        return ResponseEntity.noContent().build();
    }

    /**
     * 切换数据源启用状态
     *
     * @param id 数据源ID
     * @return 204 No Content
     */
    @PatchMapping("/{id}/toggle")
    @Operation(summary = "切换启用状态", description = "启用或禁用数据源")
    @ApiResponses({
            @ApiResponse(responseCode = "204", description = "操作成功"),
            @ApiResponse(responseCode = "404", description = "数据源不存在")
    })
    public ResponseEntity<Void> toggleEnabled(
            @Parameter(description = "数据源ID") @PathVariable Long id) {

        log.info("API: 切换数据源启用状态 - id={}", id);

        dataSourceService.toggleEnabled(id);
        return ResponseEntity.noContent().build();
    }

    /**
     * 删除数据源
     *
     * @param id 数据源ID
     * @return 204 No Content
     */
    @DeleteMapping("/{id}")
    @Operation(summary = "删除数据源", description = "删除指定的数据源配置")
    @ApiResponses({
            @ApiResponse(responseCode = "204", description = "删除成功"),
            @ApiResponse(responseCode = "404", description = "数据源不存在")
    })
    public ResponseEntity<Void> deleteDataSource(
            @Parameter(description = "数据源ID") @PathVariable Long id) {

        log.info("API: 删除数据源 - id={}", id);

        dataSourceService.deleteDataSource(id);
        return ResponseEntity.noContent().build();
    }

    /**
     * 启用数据源
     */
    @PutMapping("/{id}/enable")
    @Operation(summary = "启用数据源", description = "启用指定的数据源")
    public ResponseEntity<Void> enableDataSource(@PathVariable Long id) {
        log.info("API: 启用数据源 - id={}", id);
        dataSourceService.enableDataSource(id);
        return ResponseEntity.noContent().build();
    }

    /**
     * 禁用数据源
     */
    @PutMapping("/{id}/disable")
    @Operation(summary = "禁用数据源", description = "禁用指定的数据源")
    public ResponseEntity<Void> disableDataSource(@PathVariable Long id) {
        log.info("API: 禁用数据源 - id={}", id);
        dataSourceService.disableDataSource(id);
        return ResponseEntity.noContent().build();
    }

    /**
     * 批量启用数据源
     */
    @PostMapping("/batch/enable")
    @Operation(summary = "批量启用", description = "批量启用多个数据源")
    public ResponseEntity<Void> batchEnableDataSources(@RequestBody BatchOperationRequest request) {
        List<Long> ids = request.getIds();
        log.info("API: 批量启用数据源 - ids={}", ids);
        dataSourceService.batchEnableDataSources(ids);
        return ResponseEntity.noContent().build();
    }

    /**
     * 批量禁用数据源
     */
    @PostMapping("/batch/disable")
    @Operation(summary = "批量禁用", description = "批量禁用多个数据源")
    public ResponseEntity<Void> batchDisableDataSources(@RequestBody BatchOperationRequest request) {
        List<Long> ids = request.getIds();
        log.info("API: 批量禁用数据源 - ids={}", ids);
        dataSourceService.batchDisableDataSources(ids);
        return ResponseEntity.noContent().build();
    }

    /**
     * 批量删除数据源
     */
    @DeleteMapping("/batch")
    @Operation(summary = "批量删除", description = "批量删除多个数据源")
    public ResponseEntity<Void> batchDeleteDataSources(@RequestBody BatchOperationRequest request) {
        List<Long> ids = request.getIds();
        log.info("API: 批量删除数据源 - ids={}", ids);
        dataSourceService.batchDeleteDataSources(ids);
        return ResponseEntity.noContent().build();
    }

    /**
     * 测试数据库连接（新建数据源前）
     *
     * @param request 连接测试请求
     * @return 连接测试响应
     */
    @PostMapping("/test-connection")
    @Operation(summary = "测试数据库连接", description = "在创建数据源前测试数据库连接参数是否正确")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "测试完成（无论成功失败都返回200）",
                    content = @Content(schema = @Schema(implementation = ConnectionTestResponse.class)))
    })
    public ResponseEntity<com.insight.common.response.ApiResponse<ConnectionTestResponse>> testConnection(
            @Valid @RequestBody ConnectionTestRequest request) {

        log.info("API: 测试数据库连接 - dbType={}, host={}", request.getDbType(), request.getHost());

        ConnectionTestResponse response = connectionTestService.testConnection(request);
        return ResponseEntity.ok(com.insight.common.response.ApiResponse.success(response));
    }

    /**
     * 测试已保存数据源的连接
     *
     * @param id 数据源ID
     * @return 连接测试响应
     */
    @PostMapping("/{id}/test")
    @Operation(summary = "测试已保存数据源", description = "测试已保存数据源的数据库连接")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "测试完成",
                    content = @Content(schema = @Schema(implementation = ConnectionTestResponse.class))),
            @ApiResponse(responseCode = "404", description = "数据源不存在")
    })
    public ResponseEntity<ConnectionTestResponse> testDataSourceConnection(
            @Parameter(description = "数据源ID") @PathVariable Long id) {

        log.info("API: 测试数据源连接 - id={}", id);

        ConnectionTestResponse response = connectionTestService.testDataSourceById(id, encryptionKey);
        return ResponseEntity.ok(response);
    }

    /**
     * 获取数据源总数
     *
     * @return 数据源总数
     */
    @GetMapping("/count")
    @Operation(summary = "获取数据源总数", description = "统计系统中的数据源总数")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "查询成功")
    })
    public ResponseEntity<Map<String, Long>> countDataSources() {
        log.debug("API: 统计数据源总数");

        long count = dataSourceService.countDataSources();
        return ResponseEntity.ok(Map.of("count", count));
    }

    /**
     * 检查数据源名称是否已存在
     *
     * @param name 数据源名称
     * @return 是否存在
     */
    @GetMapping("/exists")
    @Operation(summary = "检查名称是否存在", description = "检查数据源名称是否已被使用")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "查询成功")
    })
    public ResponseEntity<Map<String, Boolean>> checkNameExists(
            @Parameter(description = "数据源名称") @RequestParam String name) {

        log.debug("API: 检查数据源名称 - name={}", name);

        boolean exists = dataSourceService.existsByName(name);
        return ResponseEntity.ok(Map.of("exists", exists));
    }

    /**
     * 全局异常处理
     */
    @ExceptionHandler(com.insight.common.exception.ResourceNotFoundException.class)
    public ResponseEntity<Map<String, String>> handleResourceNotFound(
            com.insight.common.exception.ResourceNotFoundException ex) {

        log.warn("资源不存在: {}", ex.getMessage());

        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(Map.of("message", ex.getMessage()));
    }

    @ExceptionHandler(com.insight.common.exception.DuplicateResourceException.class)
    public ResponseEntity<Map<String, String>> handleDuplicateResource(
            com.insight.common.exception.DuplicateResourceException ex) {

        log.warn("资源重复: {}", ex.getMessage());

        return ResponseEntity.status(HttpStatus.CONFLICT)
                .body(Map.of("message", ex.getMessage()));
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Map<String, String>> handleIllegalArgument(IllegalArgumentException ex) {
        log.warn("参数验证失败: {}", ex.getMessage());

        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(Map.of("message", "validation failed: " + ex.getMessage()));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Map<String, String>> handleGenericException(Exception ex) {
        log.error("未预期的异常", ex);

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(Map.of("message", "Internal server error: " + ex.getMessage()));
    }
}
